﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Security.Principal;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using SdmxMl.Manager;
using SdmxMl.Multiplexor;

namespace SdmxMl.UC
{
    public partial class ucWSImportParameters : UserControl
    {
        private string selectedFolder = string.Empty;
        private cWeBServiceLayer currentWebServiceLayer;
        private string accesKey = string.Empty;
        private string dirInfoName = "dirInfo.sms";

        public ucWSImportParameters()
        {
            InitializeComponent();
            btnCancel.Enabled = false;
        }


        #region Event definitions

        /// <summary>
        /// Event raised when user click on SELECT button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, EventArgs e)
        {
            DialogResult drSelectFolder;
            drSelectFolder=fbdSelectFolder.ShowDialog();

            if (drSelectFolder == DialogResult.OK)
            {
                // Check if folder is empty
                if(Directory.Exists(fbdSelectFolder.SelectedPath))
                {
                    var folder = new DirectoryInfo(fbdSelectFolder.SelectedPath);
                    if (folder.GetFileSystemInfos().Length == 0)
                    {
                        selectedFolder = fbdSelectFolder.SelectedPath;
                        this.tbFolderSelecter.Text=selectedFolder;
                    }
                    else
                    {
                        // Folder is not empty: show an information message
                        MessageBox.Show("Folder is not empty, please choose another one", "SDMX Import files", MessageBoxButtons.OK);
                    }
                }
            }
        }

        /// <summary>Cancel background job Event request </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            try
            {
                //Request cancellation
                bgwImportProcess.CancelAsync();
            }
            catch { }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnImport_Click(object sender, EventArgs e)
        {
            if (selectedFolder.Length > 0)
            {
                this.tbProcess.Text = string.Empty;
                try
                {
                    currentWebServiceLayer = new cWeBServiceLayer();

                    currentWebServiceLayer.WebServiceAddress = Mux.Instance.DirInfoProxy.Url;
                    // Access Key
                    string v = System.Configuration.ConfigurationManager.AppSettings["TinyRegistryVers"].ToString().Trim();
                    accesKey = v[0] == '4' ? v : "44" + v;

                    // Run the process in background
                    if (!bgwImportProcess.IsBusy)
                    {
                        btnCancel.Enabled = true;
                        btnImport.Enabled = false;
                        RunBackgroundImport();
                    }
                }
                catch
                {
                    MessageBox.Show("An error occured during the processing of your request, please try later", "SDMX Import files", MessageBoxButtons.OK);
                }
            }
            else
            {
                MessageBox.Show("Please select a destination folder", "SDMX Import files", MessageBoxButtons.OK);
            }
        }
        #endregion

        #region Private methods

        private void RunBackgroundImport()
        {
            // Prepare progressbar according to all types of artefacts
            pbImport.Minimum = 0;
            pbImport.Maximum = Enum.GetNames(typeof(SdmxArtefactType)).Length;
            pbImport.Value = 0;

            #region Initialize background worker
            bgwImportProcess = new BackgroundWorker();
            bgwImportProcess.WorkerReportsProgress = true;
            bgwImportProcess.WorkerSupportsCancellation = true;
           // bgwImportProcess.

            bgwImportProcess.DoWork += new DoWorkEventHandler(bgwImportProcess_DoWork);
            bgwImportProcess.ProgressChanged += new ProgressChangedEventHandler(bgwImportProcess_ProgressChanged);
            bgwImportProcess.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwImportProcess_RunWorkerCompleted);
            #endregion

            #region Execute work

            bgwImportProcess.RunWorkerAsync();
            #endregion

        }

        /// <summary> Inform user of progress </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void bgwImportProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            SdmxArtefactType currentArtefactType = SdmxArtefactType.None;
            foreach (SdmxArtefactType arType in Enum.GetValues(typeof(SdmxArtefactType)))
                if ((int)arType == e.ProgressPercentage)
                {
                    currentArtefactType = arType;
                    break;
                }
            if (e.UserState == null)
            {
                this.tbProcess.Text += "Process artefact type " + currentArtefactType.ToString() + Environment.NewLine;
                pbImport.Value = e.ProgressPercentage;
            }
            else
                this.tbProcess.Text += e.UserState.ToString();
        }

        /// <summary> Signal background job terminated </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void bgwImportProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                tpStatusLabel.Text = "Importation cancelled.";
            }
            else
            {

                if (e.Result.ToString().Length == 0)
                {
                    pbImport.Value = pbImport.Maximum;
                    tpStatusLabel.Text = "Importation successfully exectuted";
                }
                else
                {
                    tpStatusLabel.Text = "Importation Error: " + e.Result.ToString();
                }
            }
            btnCancel.Enabled = false;
            btnImport.Enabled = true;

        }

        /// <summary>Background job </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void bgwImportProcess_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            string diagnostic = string.Empty;
            try
            {
                // Instanciate web service
                currentWebServiceLayer.CreateProxyWebService();

                // Call web methods to get Directory Information
                tpStatusLabel.Text = "Get Artefact types list";
                List<DataSet> dsArtefactType = currentWebServiceLayer.GetDirectoryInformations();

                tpStatusLabel.Text = "Get Artefact informations";

                // Process for each Artefact type
                int arTypeIndex = 1;
                foreach (DataSet currentAretefactType in dsArtefactType)
                {
                    if (bgwImportProcess.CancellationPending)//checks for cancel request  
                    {
                        e.Cancel = true;
                        break;
                    }

                    if (currentAretefactType.Tables.Count > 0)
                    {

                        // Create the directory and the DirInfo file
                        if (!Directory.Exists(selectedFolder + "\\" + currentAretefactType.Tables[0].TableName))
                            Directory.CreateDirectory(selectedFolder + "\\" + currentAretefactType.Tables[0].TableName);

                        string dirInfoNameCurrent = selectedFolder + "\\" + currentAretefactType.Tables[0].TableName + "\\" + dirInfoName;
                        // Write the dirInfo file
                        WriteDirInfoFile(dirInfoNameCurrent,
                            currentAretefactType);

                        bgwImportProcess.ReportProgress(arTypeIndex);

                        //#if !DEBUG
                        //                        this.tbProcess.Text += "Process artefact type " + currentAretefactType.Tables[0].TableName + "\r\n";
                        //#endif 
                        // Determine user
                        string user = WindowsIdentity.GetCurrent().Name;

                        foreach (DataRow currentRow in currentAretefactType.Tables[0].Rows)
                        {
                            if (bgwImportProcess.CancellationPending)//checks for cancel request  
                            {
                                e.Cancel = true;
                                break;
                            }

                            string AgencyId = currentRow.ItemArray[2].ToString();
                            string Id = currentRow.ItemArray[0].ToString();
                            string Version = currentRow.ItemArray[1].ToString();
                            string FullId = AgencyId + "+" + Id + "+" + Version;

                            XmlElement currentElement = currentWebServiceLayer.GetArtefactOs(user,
                                accesKey,
                                currentAretefactType.Tables[0].TableName,
                                FullId);

                            XmlAttribute returnAttribute;
                            try { returnAttribute = currentElement.FirstChild.Attributes[0]; }
                            catch { returnAttribute = null; }

                            bool bHasAttribute = returnAttribute != null;
                            bool bIsFailed = false;
                            if (bHasAttribute)
                            {
                                if (returnAttribute.Name.ToUpper().Equals("STATUS") &&
                                    returnAttribute.Value.ToUpper().Equals("FAILURE"))
                                {
                                    bgwImportProcess.ReportProgress(arTypeIndex, "Failed to retrieve information on " + FullId);
                                    diagnostic = "Some artefact failure detected";
                                    //#if !DEBUG

                                    //#endif
                                    bIsFailed = true;
                                }
                            }
                            if (!bIsFailed)
                                WriteArtefact(currentElement,
                                    selectedFolder,
                                    currentAretefactType.Tables[0].TableName,
                                    FullId);

                        }

                    }
                    ++arTypeIndex;
                }
            }
            catch (Exception ex)
            {
                diagnostic = ex.Message;
            }

            e.Result = diagnostic;
        }
        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="dsArtefact"></param>
        private void WriteDirInfoFile(string filename,
            DataSet dsArtefact)
        {
            XmlWriterSettings writerSettings = new XmlWriterSettings();
            writerSettings.Indent = true;

            if (File.Exists(filename))
                File.Delete(filename);
            XmlWriter xmlWriter = XmlWriter.Create(filename, writerSettings);
            dsArtefact.WriteXml(xmlWriter, XmlWriteMode.WriteSchema);
            xmlWriter.Flush();
            xmlWriter.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xmlArtefact"></param>
        private void WriteArtefact(XmlElement xmlArtefact,
            string sPath,
            string artefactType,
            string fullId)
        {

            XmlWriterSettings writerSettings = new XmlWriterSettings();
            writerSettings.Indent = true;
            writerSettings.Encoding = Encoding.UTF8;
            writerSettings.OmitXmlDeclaration = true;

            // Save the file
            XmlWriter xmlWriter = XmlWriter.Create(sPath + "\\" + artefactType + "\\" + fullId + ".xml", writerSettings);
            xmlArtefact.WriteTo(xmlWriter);
            xmlWriter.Flush();
            xmlWriter.Close();
        }

        #endregion
    }


    #region Define class cWebServiceLayer
    /// <summary>
    /// This class is used to acces to the Web Service TinyRegistry
    /// </summary>
    class cWeBServiceLayer
    {
        #region Public properties
        public string WebServiceAddress = string.Empty;
        public SdmxMl.TinyRegistry.Repository currentRepository;
        #endregion

        #region Private members
        #endregion

        #region Constructor(s)

        #endregion

        #region Public methods

        public XmlElement GetArtefactOs(string user,
            string accessKey,
            string artefactType,
            string fullId
            )
        {
            XmlElement xmlReturn = null;
                xmlReturn = currentRepository.GetArtefactOS(user, accessKey, artefactType, fullId);

            return (xmlReturn);
        }

        public List<DataSet> GetDirectoryInformations()
        {
            List<DataSet> dsReturn = new List<DataSet>();

               // Need to parse all Artefact Type
               foreach (SdmxArtefactType arType in Enum.GetValues(typeof(SdmxArtefactType)))
                {
                    if (arType != SdmxArtefactType.None)
                    {
                        DataSet dsArtefactType = currentRepository.DirInfo(arType.ToString());
                        dsReturn.Add(dsArtefactType);
                    }
                }

            return (dsReturn);
        }

        /// <summary>
        /// Instanciate a repository web service
        /// </summary>
        public void CreateProxyWebService()
        {
            if (currentRepository == null)
                currentRepository = new SdmxMl.TinyRegistry.Repository();
            currentRepository.Url = this.WebServiceAddress;
        }

        #endregion

        #region Private methods
        #endregion
    }
    
    #endregion

}
